﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace SQL_Manager.OTServ
{
    sealed public class Account
    {
        //TODO: Function to list all accounts (required for accounts lookup form)
        private Hashtable _Data;
        private Database Db;

        #region Constructors

        //
        // Constructor for a new account
        //
        public Account()
        {
            this._Data = new Hashtable();
            this.password = string.Empty;
            this.email = string.Empty;
            this._Data["new"] = true;
            this.blocked = 0;
            this.name = string.Empty;
        }

        //
        // Get account by ID
        //
        public Account(uint Account)
        {
            Database.GetInstance(out this.Db);
            this.__retrieve(Account);
        }

        //
        // Get account by Account Name
        //
        public Account(string Account)
        {
            Database.GetInstance(out this.Db);
            this.__retrieve(Account);
        }

        //
        // Get account by ID
        // - Assigns account by reference
        //
        public Account(uint Account, out Account account)
        {
            Database.GetInstance(out this.Db);
            this.__retrieve(Account);
            account = this;
        }

        //
        // Get account by Account Name
        //- Assigns account by reference
        //
        public Account(string Account, out Account account)
        {
            Database.GetInstance(out this.Db);
            this.__retrieve(Account);
            account = this;
        }

        //
        // Used to manually load the account (id must be set)
        //
        public void load()
        {
            this.__retrieve(this.id);
        }

        #endregion

        #region Database-Related

        //
        // This saves every field, including custom ones.. since we did load them all
        // - This returns the # of rows affected; 0 is NO ROWS, which means it failed.
        //
        public int commit()
        {
            if (this._Data["id"] != null)
            {
                StringBuilder gstring = new StringBuilder("UPDATE accounts SET ");

                foreach (System.Collections.DictionaryEntry entry in this._Data)
                {
                    gstring.AppendFormat("{0}='{1}',", entry.Key, entry.Value);
                }

                gstring.Remove(gstring.Length - 1, 1);
                gstring.AppendFormat(" WHERE id = {0}", this._Data["id"]);

                return this.Db.execute(gstring.ToString());
            }
            else
            {
                StringBuilder fields = new StringBuilder("INSERT INTO accounts (");
                StringBuilder values = new StringBuilder(" VALUES(");

                foreach (System.Collections.DictionaryEntry entry in this._Data)
                {
                    fields.AppendFormat("{0},", entry.Key);
                    values.AppendFormat("'{0}',", entry.Value);
                }

                fields.Remove(fields.Length - 1, 1); // remove ,
                values.Remove(values.Length - 1, 1); // remove ,
                fields.AppendFormat(") {0})", values.ToString());

                return this.Db.execute(fields.ToString());
            }
        }

        //
        // This loads the account by Account Name
        //
        private void __retrieve(string account)
        {
            this.Db.query(string.Format("SELECT * FROM accounts WHERE name = '{0}'", account), out this._Data);
            
            if (this._Data.Count == 0)
            {
                throw new Exceptions.AccountNotFoundException();
            }
        }

        //
        // This loads the account by Account ID
        //
        private void __retrieve(uint account)
        {
            this.Db.query(string.Format("SELECT * FROM accounts WHERE id = {0}", account), out this._Data);

            if (this._Data.Count == 0)
            {
                throw new Exceptions.AccountNotFoundException();
            }
        }

        #endregion

        #region Properties

        public uint id
        {
            get
            {
                if (this._Data["id"] == null)
                {
                    return 0;
                }

                return Convert.ToUInt32(this._Data["id"]);
            }
        }

        public string name
        {
            get
            {
                return (string)this._Data["name"];
            }
            set
            {
                this._Data["name"] = value;
            }
        }

        public string password
        {
            get
            {
                return (string)this._Data["password"];
            }
            set
            {
                this._Data["password"] = value;
            }
        }

        public string email
        {
            get
            {
                return (string)this._Data["email"];
            }
            set
            {
                this._Data["email"] = value;
            }
        }

        public uint premend
        {
            get
            {
                return Convert.ToUInt32(this._Data["premend"]);
            }
            set
            {
                this._Data["premend"] = value;
            }
        }

        public ushort blocked
        {
            get
            {
                return Convert.ToUInt16(this._Data["blocked"]);
            }
            set
            {
                this._Data["blocked"] = value;
            }
        }

        public int warnings
        {
            get
            {
                return Convert.ToInt32(this._Data["warnings"]);
            }
            set
            {
                this._Data["warnings"] = value;
            }
        }

        #endregion
    }
}
